package com.tom.architect02.ui30.day24;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import androidx.annotation.Nullable;

import com.tom.architect02.ui30.day25.BubbleMessageTouchListener;
import com.tom.architect02.ui30.day25.BubbleUtils;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.view.animation.OvershootInterpolator;

/**
 * Added by Tom on 2024/06/21.
 */
public class MessageBubbleView extends View {
    private Context mContext;
    private PointF mFixationPoint, mDragPoint; // 起始点，拖拽点
    private int mDragRadius = 10; // 拖拽圆的半径，是固定的
    private int mFixationRadius; // 计算得到真实的半径
    private int mFixationRadiusMax = 7; // 最大半径
    private int mFixationRadiusMin = 2;
    private Paint mPaint;
    private Bitmap mDragBitmap; // 拖动View的快照


    public MessageBubbleView(Context context) {
        this(context, null);
    }

    public MessageBubbleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MessageBubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        mDragRadius = dip2px(mDragRadius);
        mFixationRadiusMax = dip2px(mFixationRadiusMax);
        mFixationRadiusMin = dip2px(mFixationRadiusMin);

        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setDither(true);
        mPaint.setAntiAlias(true);
    }

    private int dip2px(int dip) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
    }


    @Override
    protected void onDraw(Canvas canvas) {
        if (mDragPoint == null || mFixationPoint == null) return;
        // 画2个圆圈
        canvas.drawCircle(mDragPoint.x, mDragPoint.y, mDragRadius, mPaint);

        // 固定圆有初始大小，半径随距离增大而减小。且小到一定程度就不见了。
        Path bezierPath = getBezierPath();
        if (bezierPath != null) {
            canvas.drawCircle(mFixationPoint.x, mFixationPoint.y, mFixationRadius, mPaint);
            canvas.drawPath(bezierPath, mPaint);
        }
        // 绘制图片快照: 图片的中心位置，是手指的move位置。
        if (mDragBitmap != null) {
            canvas.drawBitmap(mDragBitmap, mDragPoint.x - mDragBitmap.getWidth() / 2,
                    mDragPoint.y - mDragBitmap.getHeight() / 2, null);
        }
    }

    private Path getBezierPath() {
        double distance = getDistance(mDragPoint, mFixationPoint);
        mFixationRadius = (int) (mFixationRadiusMax - distance / 14);
        if (mFixationRadius < mFixationRadiusMin) {
            // 超过一定距离，不绘制贝塞尔和固定圆。
            return null;
        }
        // 求角度a, 先拿到斜率
        float dy = mDragPoint.y - mFixationPoint.y;
        float dx = mDragPoint.x - mFixationPoint.x;
        float tanA = dy / dx;
        double arcTanA = Math.atan(tanA);

        // 求p0位置
        float p0x = (float) (mFixationPoint.x + mFixationRadius * Math.sin(arcTanA));
        // 往0点方向，所以要- 对应的值。
        float p0y = (float) (mFixationPoint.y - mFixationRadius * Math.cos(arcTanA));
        // 求p1位置
        float p1x = (float) (mDragPoint.x + mDragRadius * Math.sin(arcTanA));
        float p1y = (float) (mDragPoint.y - mDragRadius * Math.cos(arcTanA));

        // p2
        float p2x = (float) (mDragPoint.x - mDragRadius * Math.sin(arcTanA));
        float p2y = (float) (mDragPoint.y + mDragRadius * Math.cos(arcTanA));
        // p3
        float p3x = (float) (mFixationPoint.x - mFixationRadius * Math.sin(arcTanA));
        float p3y = (float) (mFixationPoint.y + mFixationRadius * Math.cos(arcTanA));


        // 拼装贝塞尔曲线路径。
        Path bezierPath = new Path();
        bezierPath.moveTo(p0x, p0y);
        // 选2点的 中间点为控制点。
        PointF controlPoint = getControlPoint();
        bezierPath.quadTo(controlPoint.x, controlPoint.y, p1x, p1y);

        // 画第二条
        bezierPath.lineTo(p2x, p2y); // 形成闭合
        bezierPath.quadTo(controlPoint.x, controlPoint.y, p3x, p3y);
        bezierPath.close();

        return bezierPath;
    }

    // 求两点之间的中间点。
    private PointF getControlPoint() {
        return new PointF((mDragPoint.x + mFixationPoint.x) / 2, (mDragPoint.y + mFixationPoint.y) / 2);
    }

    // 获取两点的距离
    private double getDistance(PointF p1, PointF p2) {
        float dx = p1.x - p2.x;
        float dy = p1.y - p2.y;
        return Math.sqrt(dx * dx + dy * dy);
    }


   /* @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                initPoint(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                updateDragPoint(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_UP:
                mFixationPoint = null;
                mDragPoint = null;
                break;
        }
        invalidate();// 源码分析：todo
        return true;
    }*/

    // 更新拖拽点的坐标。
    public void updateDragPoint(float x, float y) {
        mDragPoint.x = x;
        mDragPoint.y = y;
        invalidate();
    }

    public void initPoint(float x, float y) {
        mFixationPoint = new PointF(x, y);
        mDragPoint = new PointF(x, y);
        invalidate();
    }


    //---------------------------------
    /**
     * 绑定可以拖拽的空间
     *
     * @param view
     * @param disappearListener
     */
    public static void attach(View view, BubbleMessageTouchListener.BubbleDisappearListener disappearListener) {
        view.setOnTouchListener(new BubbleMessageTouchListener(view, view.getContext(),disappearListener));
    }

    public void setDragBitmap(Bitmap bitmap) {
        this.mDragBitmap = bitmap;
    }

    // 处理手指松开
    public void handleActionUp() {
        if (mFixationRadius > mFixationRadiusMin) {
            // 要回弹：ValueAnimator 值变化的动画  0 变化到 1
            ValueAnimator animator = ObjectAnimator.ofFloat(1); // 值变化的动画
            animator.setDuration(250);
            final PointF start = new PointF(mDragPoint.x, mDragPoint.y); // 起点
            final PointF end = new PointF(mFixationPoint.x, mFixationPoint.y); // 最终终点
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float percent = (float) animation.getAnimatedValue();// 0 - 1
                    // 从一个点，沿直线移动到另一个点。
                    PointF pointF = BubbleUtils.getPointByPercent(start, end, percent);
                    // 用代码更新拖拽点, 模拟手指拖动。
                    updateDragPoint(pointF.x, pointF.y);
                }
            });
            // 设置一个差值器: 在结束的时候回弹
            animator.setInterpolator(new OvershootInterpolator(5f));
            animator.start();

            // 还要通知 TouchListener 移除当前View 然后显示静态的 View
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    if (mListener != null) {
                        mListener.restore();
                    }
                }
            });
        } else { // 要爆炸消失
            // 爆炸
            if (mListener != null) {
                mListener.dismiss(mDragPoint);
            }
        }
    }

    //region 回调接口
    private MessageBubbleListener mListener;
    public void setMessageBubbleListener(MessageBubbleListener listener) {
        this.mListener = listener;
    }
    public interface MessageBubbleListener {
        // 还原
        void restore();
        // 消失爆炸
        void dismiss(PointF pointF);
    }
    //endregion

}

//3.1 有两个圆，一个是固定圆位置固定不动但是半径会变化（两个圆之间的距离越远半径就越小），
//        还有一个是拖拽圆半径是不变的位置是跟随我手指移动
//        3.2 在两个圆之间中间会有一个粘性的不规则图像（贝塞尔曲线）